// OGoMojo
// Whitemice.MOGI.HashCache
// License: LGPL
// Copyright: Whitemice Consulting, 2006
// Author(s): Adam Tauno Williams (awilliam@whitemice.org)
using System;
using System.Collections;

namespace Whitemice.MOGI 
{
	public class HashCache : ICache
	{
		protected Hashtable	documentCache;
		protected Hashtable	searchCache;
		protected CachePolicy defaultPolicy;
		protected IServer		server;
		
		public HashCache(IServer server, CachePolicy policy)
		{
			defaultPolicy = policy;
			documentCache = new Hashtable();
			searchCache = new Hashtable();
			this.server = server;
		}
	
		public void Purge()
		{
			documentCache = new Hashtable();
			searchCache = new Hashtable();
		}
		
		public uint Flush()
		{
			uint 	count;
			ArrayList purgeQueue;
			
			purgeQueue = new ArrayList();
			count = 0;
			foreach(HashCacheEntry entry in documentCache)
				if (entry.IsAlive())
				{
					if (entry.IsModified)
						if(entry.Payload is IDocument)
						{
							server.Put((IDocument)entry.Payload);
							count++;
						}
				} else if (!(entry.Name == null)) 
					purgeQueue.Add(entry.Name);
			return count;
		}
		
		public bool Contains(string document)
		{
			if (documentCache.Contains(document))
				if (((HashCacheEntry)documentCache[document]).IsAlive())
				{
					server.Log.Debug("HashCache::Contains(" + document + ") - Cache contains");				
					return true;
				}	
			server.Log.Debug("HashCache::Contains(" + document + ") - Cache does not contain");
			return false;
		}
		
		public IDocument Get(string document)
		{				
			server.Log.Debug("HashCache::Get(" + document + ")");		
			if(documentCache.Contains(document))
				if(((HashCacheEntry)documentCache[document]).IsAlive())
					return (IDocument)((HashCacheEntry)documentCache[document]).Payload;
			return null;
		}
		
		public ArrayList Search(string criteria)
		{
			server.Log.Debug("HashCache::Search(" + criteria + ")");
			if(searchCache.Contains(criteria))
			{
				ArrayList results;
				
				server.Log.Debug("HashCache::Search(" + criteria + ") - Cache has search");
				results = new ArrayList();
				foreach(string name in (ArrayList)((HashCacheEntry)searchCache[criteria]).Payload)
					if(documentCache.Contains(name))
						if(((HashCacheEntry)documentCache[name]).IsAlive())
						{
							server.Log.Debug("HashCache::Search(" + criteria + ") - Adding to search result " + name);
							results.Add(((HashCacheEntry)documentCache[criteria]).Payload);
						} else 
							{
								server.Log.Debug("HashCache::Search(" + criteria + ") - Inactive object, abandoning search results");
								return null;
							}
				server.Log.Debug("HashCache::Search(" + criteria + ") - " + results.Count.ToString() + " objects in search results");
				return results;
			}
			server.Log.Debug("HashCache::Search(" + criteria + ") - Cache does not contain search.");
			return null;
		}
		
		public IDocument Put(IDocument document)
		{
			server.Log.Debug("HashCache::Put(" + document.Name + ")");
			if (documentCache.Contains(document.Name))
				((HashCacheEntry)documentCache[document.Name]).Store(document);
			else
				documentCache.Add(document.Name, new HashCacheEntry(document, defaultPolicy));
			return document;
		}
		
		public ArrayList Put(string criteria, ArrayList results)
		{
			server.Log.Debug("HashCache::Put(" + criteria + ", [ArrayList])");		
			if (!(results == null))
			{
				ArrayList documentList;
				documentList = new ArrayList();
				foreach(IDocument document in results)
				{
					Put(document);
					documentList.Add(document.Name);
					server.Log.Debug("HashCache::Put(...) - " + results.Count.ToString() + " documents stored");							
				}
				if (searchCache.Contains(criteria))
					searchCache[criteria] = documentList;
					else searchCache.Add(criteria, documentList);
			}
			return results;
		}
		
		public ArrayList Documents(DocumentType type)
		{
			ArrayList results;
			
			server.Log.Debug("HashCache::Documents(" + type.ToString() + ")");					
			results = new ArrayList();
			foreach(HashCacheEntry entry in documentCache)
				if(entry.Type == type)
					results.Add(entry.Payload);
			return results;
		}
	}
}